<script setup lang="ts">
import { nextTick, onMounted, ref, reactive, onUnmounted, onBeforeMount } from 'vue'
import 'xterm/css/xterm.css'
import 'xterm/lib/xterm.js'
import { IBufferRange, IDecoration, IDecorationOptions, IDisposable, ILinkProvider, IMarker, ITerminalAddon, Terminal } from 'xterm'
// xterm.js的插件，使终端的尺寸适合包含元素。
import { FitAddon } from 'xterm-addon-fit'
// xterm.js的附加组件，用于附加到Web Socket
import { AttachAddon } from 'xterm-addon-attach'
let wsTime: any = reactive<any>("");
const terminal = ref();
let url = "ws://127.0.0.1:5555"
let ws: WebSocket = reactive<WebSocket>(new WebSocket(url));
let term: Terminal = reactive<Terminal>(new Terminal({
  rows: 40, //行数，影响最小高度
  cols: 100, // 列数，影响最小宽度
  convertEol: true, //启用时，光标将设置为下一行的开头
  scrollback: 50, //终端中的滚动条回滚量
  disableStdin: false, //是否应禁用输入。
  cursorStyle: "underline", //光标样式
  cursorBlink: true, //光标闪烁
  theme: {
    foreground: "#F8F8F8",
    background: "#2D2E2C",
    cursor: "help", //设置光标

  },
  fontFamily: '"Cascadia Code", Menlo, monospace',
}));


// 用户输入
let command: String = reactive<String>("");
onBeforeMount(() => {
  initTerm()
})
onMounted(() => {
  websocket()
});
onUnmounted(() => {
  ws.close();
  term.dispose();
})
function initTerm() {
  // term = new Terminal({
  //   // rows: 40, //行数，影响最小高度
  //   cols: 100, // 列数，影响最小宽度
  //   convertEol: true, //启用时，光标将设置为下一行的开头
  //   // scrollback: 50, //终端中的滚动条回滚量
  //   disableStdin: false, //是否应禁用输入。
  //   cursorStyle: "underline", //光标样式
  //   cursorBlink: true, //光标闪烁
  //   theme: {
  //     foreground: "#F8F8F8",
  //     background: "#2D2E2C",
  //     cursor: "help", //设置光标

  //   },
  //   fontFamily: '"Cascadia Code", Menlo, monospace',
  // })
}

function websocket() {
  if ("WebSocket" in window) {
    //需要修改ip和id
    //例如：const url = `ws://192.168.111.222:2375/v1.41/containers/0eb8aafb4e6e/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1`
    const url = `ws://127.0.0.1:5555`;
    //ws = new WebSocket(url);

    nextTick(() => {
      userWrite();
    });
    ws.onopen = (event) => {
      console.log("已建立连接：", event);
      // 输入换行符可让终端显示当前用户的工作路径
      // ws.send("\n");//这边原来是放开状态,但由于后台数据返回原因会报错,就直接注释了
      // 窗口自适应插件
      // 窗口尺寸变化时，终端尺寸自适应
      let fitAddon: FitAddon = new FitAddon();
      //websocket自动收发消息插件
      let attachAddon: AttachAddon = new AttachAddon(ws, { bidirectional: false })

      //attachAddon.activate(term)
      //fitAddon.activate(term)
      //给新的这个ws服务使用依赖设置样式
      term.loadAddon(fitAddon);
      //给新的这个ws服务使用依赖初始化
      term.loadAddon(attachAddon)
      term.open(terminal.value);
      // // 聚焦闪烁光标
      term.focus();
      ////先默认一次适应大小
      setTimeout(() => {
        fitAddon.fit();
      }, 1000)
      window.onresize = () => {
        fitAddon.fit();
      };
      // 自定义终端默认展示内容
      writeDefaultInfo();
    };
    ws.onmessage = (event) => {
      // console.log("接收信息event.data：", event.data);
      // let message = "\n" + JSON.parse(event.data).message;
      // console.log("接收信息message ：", message);
      // //根据后台返回数据进行处理成对象形式进行显示到页面,如果不需要处理,需要直接将字符串转换成 Blob对象
      // const blob = new Blob([message], {
      //   type: "text/plain",
      // });
      // //将Blob 对象转换成字符串
      // const reader = new FileReader();
      // reader.readAsText(blob, "utf-8");
      // reader.onload = (e) => {
      //   // 可以根据返回值判断使用何种颜色或者字体，不过返回值自带了一些字体颜色
      //   writeOfColor(message, "0;", "37m");
      // };
    };
    ws.onerror = (event) => {
      console.log("错误信息：", event);
      if (wsTime) {
        window.clearTimeout(wsTime);
        wsTime = null;
      }
      wsTime = window.setTimeout(() => {
        websocket();
      }, 3000);
    };
    ws.onclose = (event) => {
      console.log("已关闭连接：", event);
      // if (wsTime) {
      //    window.clearTimeout(wsTime)
      //    wsTime = null
      // }
      // wsTime = window.setTimeout(() => {
      //    this.websocket()
      // }, 3000)
    };
    //const socket = new WebSocket('ws://127.0.0.1:5555')

  } else {
    console.log("浏览器不支持 WebSocket..");
  }
}
// 自定义终端默认展示内容
function writeDefaultInfo() {
  let defaultInfo = [
    "┌\x1b[1m terminals \x1b[0m─────────────────────────────────────────────────────────────────┐ ",
    "│                                                                            │ ",
    "│  \x1b[1;34m 欢迎使用Web Docker SSH \x1b[0m                                                  │ ",
    "│                                                                            │ ",
    "└────────────────────────────────────────────────────────────────────────────┘ ",
  ];
  // 测试颜色区间
  // let arr = Array.from({length:100},(v,i)=>v = i)
  // console.log(arr)
  // arr.map((item,i) => {
  //     defaultInfo.push(`Hello from \x1B[1;3;${i}m ${i} \x1B[0m  \u2764\ufe0f   ${i}`)
  // })
  term.write(defaultInfo.join("\n\r"));
  writeOfColor("\n\r我是加粗斜体红色的字呀", "1;3;", "31m");
  // term.write('\n\r$ ')
};
//
function writeOfColor(txt: string | ArrayBuffer | null, fontCss = "", bgColor = "") {
  // 在Linux脚本中以 \x1B[ 开始，中间前部分是样式+内容，以 \x1B[0m 结尾
  // 示例 \x1B[1;3;31m 内容 \x1B[0m
  // fontCss
  // 0;-4;字体样式（0;正常 1;加粗 2;变细 3;斜体 4;下划线）
  // bgColor
  // 30m-37m字体颜色（30m:黑色 31m:红色 32m:绿色 33m:棕色字 34m:蓝色 35m:洋红色/紫色 36m:蓝绿色/浅蓝色 37m:白色）
  // 40m-47m背景颜色（40m:黑色 41m:红色 42m:绿色 43m:棕色字 44m:蓝色 45m:洋红色/紫色 46m:蓝绿色/浅蓝色 47m:白色）
  term.write(`\x1B[${fontCss}${bgColor}${txt}\x1B[0m`);
};
function tt() {
  console.log("tt")
  ws.close();
  term.dispose();
}
// 监听输入
function userWrite() {
  term.onData((e) => {
    switch (e) {
      case "\u0003": // Ctrl+C
        term.write("^C ");
        term.write("\r\n$ ");
        break;
      case "\r": // Enter
        if (command == "clear") {
          term.clear()
          command = "";
        } else {
          ws.send(JSON.stringify({ message: command }));//根据后台返回的数据,需要传入一个对象,里边key值为message,并对这个对象进行序列化
          // this.ws.send("\n");//这边原来是放开状态,但由于后台数据返回原因会报错,就直接注释了
          command = "";
          term.write('\r\n$ ')
        }

        break;
      case "\u007F": // Backspace (DEL)
        // Do not delete the prompt
        console.log("{}:", term)
        term.write("\b \b");
        if (command.length > 0) {
          command = command.substr(
            0,
            command.length - 1
          );
        }
        break;
      default: // Print all other characters for demo
        if (
          (e >= String.fromCharCode(0x20) &&
            e <= String.fromCharCode(0x7e)) ||
          e >= "\u00a0"
        ) {
          command += e;
          writeOfColor(e, "2;3;", "33m");
          console.log("用户输入command", command);
        }
    }
  });
}
</script>

<template>
  <div ref="terminal" id="Terminal" class="xterm"></div>
  <!-- <button @click="tt">close</button> -->
</template>
<style scoped>
.xterm {
  width: 100%;
  height: 100%;
  border: 1px solid #ccc;
}
</style>
